#!/usr/bin/env python

# --------------------------------
# projects/python/matlab/MatLab.py
# Copyright (C) 2009
# Yersain Ospanov
# --------------------------------

import random

# ---
# add
# ---

'''
addition with a scalar
addition with a matrix
must be the same size
'''
def add (m, n) :
    """
    This method returns a matice which is an addition of two matrices or a matric with is addition a matric and a scalar
    """
    answer =()
    if type(m) is tuple and type(n) is tuple:
	assert len(m)== len(n)
	assert len(m[0])== len(n[0])
        index1 = 0
        temp1 = ()
        temp2 = ()
        while index1 < len(m):
            temp1 = m[index1]
            temp2 = n[index1]
            index1+=1
            index2 = 0
            temp3 = ()
            while index2 < len(m[0]):
                temp3 += ((temp1[index2] + temp2[index2]), )
                index2+=1
            answer+=(temp3, )
    elif type(m) is tuple and type(n) is int:
        for v in m:
            temp1 = ()
            for w in v:
                temp1+=((w+n),)
            answer+=(temp1, )
    else:
        for v in n:
            temp1 = ()
            for w in v:
                temp1+=((w+m),)
            answer+=(temp1, )
    return answer


# --------
# subtract
# --------

'''
subtraction with a scalar
subtraction with a matrix
must be the same size
'''
def subtract (m, n) :
    """
    This method returns a matrice which is an subtraction of two matrices or a subtraction of a matric and a scal$
    """
    answer =()
    if type(m) is tuple and type(n) is tuple:
	assert len(m)== len(n)
	assert len(m[0]) == len(n[0])
        index1 = 0
        temp1 = ()
        temp2 = ()
        while index1 < len(m):
            temp1 = m[index1]
            temp2 = n[index1]
            index1+=1
            index2 = 0
            temp3 = ()
            while index2 < len(m[0]):
                temp3 += ((temp1[index2] - temp2[index2]), )
                index2+=1
            answer+=(temp3, )
    elif type(m) is tuple and type(n) is int:
        for v in m:
            temp1 = ()
            for w in v:
                temp1+=((w-n),)
            answer+=(temp1, )
    else:
        for v in n:
            temp1 = ()
            for w in v:
                temp1+=((w-m),)
            answer+=(temp1, )
    return answer
# --------
# multiply
# --------

'''
multiplication with a scalar
multiplication with a matrix
must be compatible sizes
'''
def multiply (m, n) :
    """
    This method returns a multiplication of two matrices or a matrice which is a multiplication of a matric and a scalar
    """
    answer =()
    if type(m) is tuple and type(n) is tuple:
	assert len(m[0])== len(n)
        row_ind = 0
        while row_ind < len(m):
            row = m[row_ind]
            row_ind+=1
            sum = 0
            col_ind=0
            col_len = 0
            temp=()
            c=0
            while c < len(n[0]):
                col_len+=1
                col=()
                while col_ind<len(n):
                    row_temp = n[col_ind]
                    col+=(row_temp[c],)
                    col_ind+=1
                c+=1
                col_ind=0
                index = 0
                while index < len(row):
                    sum+= row[index]*col[index]
                    index+=1
                index=0
                temp+=(sum,)
                sum=0
            answer+=(temp, )
    elif (type(m) is tuple and type(n) is int) :
        for v in m:
            temp1 = ()
            for w in v:
                temp1+=((w*n),)
            answer+=(temp1, )
    else:
        for v in n:
            temp1 = ()
            for w in v:
                temp1+=((w*m),)
            answer+=(temp1, )
    return answer


# -----
# slice
# -----

'''
cth column
'''
def slice_col (m, c) :
    """
    This method returns a specified colunm r in a matric m
    """
    assert len(m) > 0
    assert c >=0
    assert c < len(m[0])
    answer=()
    index1=0
    while index1<len(m):
        row = m[index1]
        answer+=(row[c],)
        index1+=1
    return answer

'''
rth column
'''
def slice_row (m, r) :
    """
    This method returns a row r in a given matrice m
    """
    assert len(m) > 0
    assert r >=0
    assert r < len(m)
    if len(m)>r:
        answer = list(m[r])
    else:
        answer = ()
    return tuple(answer)

# ------
# concat
# ------

'''
concatenation of the columns
must be compatible sizes
'''
def concat_cols (m, n) :
    """
    This method returns a matrice which is a concatination of columns of two matrices m and n
    """
    assert len(m) > 0
    assert len(m[0]) == len(n[0])
    answer = list(m)
    if len(m[0]) == len(n[0]):
        index = 0
        while index < len(n):
            answer.append(slice_row(n,index))
            index+=1
    return tuple(answer)

'''
concatenation of the rows
must be compatible sizes
'''
def concat_rows (m, n) :
    """
    This method returns a matrice which is a concationa of rows of two matrices m and n
    """
    answer = ()
    if len(m) == len(n):
            index2=0
            while index2<len(m):
                temp=()
                temp+=slice_row(m,index2)
                temp+=slice_row(n,index2)
                answer+=(temp,)
                index2+=1
    return answer

# ----
# diag
# ----

'''
diagonal of the matrix
'''
def diag (m) :
    """
    This method returns a diagonal of matrice m
    """
    assert len(m) > 0
    answer=()
    index1=0
    if len(m)>0:
        while index1<len(m[0]):
            if index1==len(m):   
                break
            index2=0
            temp1=m[index1]
            while index2<len(m):
                if index1==index2:
                    answer+=(temp1[index2],)
                index2+=1
            index1+=1
    return answer

# ---
# eye
# ---

'''
identity matrix
'''
def eye (r, c) :
    """
    This method returns an identity matrice with r number of rows and c number of columns
    """
    assert r >=0
    assert c >=0
    answer=()
    index1=0
    while index1<r:
        index2=0
        temp=()
        while index2<c:
            if index1==index2:
                temp+=(1,)
            else:
                temp+=(0,)
            index2+=1
        index1+=1
        answer+=(temp,)
    return answer
# ----
# ones
# ----

'''
matrix of ones
'''
def ones (r, c) :
    """
    This method return a matrix of ones with r number of rows and c number of columns
    """
    assert r>=0
    assert c>=0
    answer=()
    index1=0
    while index1<r:
        index2=0
        temp=()
        index1+=1
        while index2<c:
            temp+=(1,)
            index2+=1
        answer+=(temp,)
    return answer

# ----
# rand
# ----

'''
matrix of random values
'''
def rand (r, c) :
    """
    This method returns a matrix of random values with r number of rows and c number of columns
    """
    assert r>=0
    assert c>=0
    assert r<len(m)
    assert c<len(m[0])
    rand = random.randint(-2147483647,2147483647) 
    answer=()
    index1=0
    while index1<r:
        index2=0
        temp=()
        while index2<c:
            temp+=(rand,)
            rand=random.randint(-2147483647,2147483647)    

            index2+=1
        index1+=1
        answer+=(temp,)
    return answer
    


# ---
# sum
# ---

'''
sum of the columns
'''
def sum_cols (m) :
    """
    This method returns sum of columns in a given matrix m
    """
    assert len(m) > 0
    answer = list(m[0])
    index = 1
    temp = ()
    while index < len(m):
        temp = m[index]
        index2=0
        while index2<len(answer):
            answer[index2]+=temp[index2]
            index2+=1
        index+=1
    return tuple(answer)

'''
sum of the rows
'''
def sum_rows (m) :
    """
    This method returns sum of rows of a given matrix
    """
    assert len(m) > 0
    answer=()
    index1=0
    while index1 < len(m) :
        temp = list(m[index1])
        index1+=1
        index2=0
        sum = 0
        while index2<len(temp):
            sum+=temp[index2]
            index2+=1
        answer+=(sum,)
    return answer

# ---------
# transpose
# ---------

'''
swap the rows and columns
'''
def transpose (m) :
    """
    This method return a matrix which is swapped the raws and columns of a given matrix m
    """
    assert len(m) > 0
    answer = ()
    c = 0
    if len(m)>0:
        while c < len(m[0]):
            answer+= (slice_col(m,c),)
            c+=1
    return answer

# ---
# tri
# ---

'''
lower triangular
'''
def tril (m) :
    """
    This method returns a lower triangle of a matrix m
    """
    assert len(m) > 0
    answer = ()
    index1=0
    while index1< len(m[0]):
        index2=0
        temp=()
        row = m[index1]
        while index2 < len(m):
            if index1 <= index2:
                temp+=(0,)
            else:
                temp+= (row[index2],)
            index2+=1
        index1+=1
        answer+=(temp,)
    return answer


'''
upper triangular
'''
def triu (m) :
    """
    This method returns an upper triangle of a matrix m
    """
    assert len(m) >0
    answer = ()
    index1=0
    while index1< len(m[0]):
        index2=0
        temp=()
        row = m[index1]
        while index2 < len(m):
            if index1 >= index2:
                temp+=(0,)
            else:
                temp+= (row[index2],)
            index2+=1
        index1+=1
        answer+=(temp,)
    return answer


# -----
# zeros
# -----

'''
matrix of zeros
'''
def zeros (r, c) :
    """
    This method returns a matrix of zeros
    """
    assert r>=0
    assert c>=0
    answer=()
    index1=0
    while index1<r:
        index2=0
        temp=()
        index1+=1
        while index2<c:
            temp+=(0,)
            index2+=1
        answer+=(temp,)
    return answer

